# 题目: 1894. 找到需要补充粉笔的学生编号

一个班级里有 n 个学生,编号为 0 到 n - 1 。每个学生会依次回答问题,编号为 0 的学生先回答,然后是编号为 1 的学生,以此类推,直到编号为 n - 1 的学生,然后老师会重复这个过程,重新从编号为 0 的学生开始回答问题。

给你一个长度为 n 且下标从 0 开始的整数数组 chalk 和一个整数 k 。一开始粉笔盒里总共有 k 支粉笔。当编号为 i 的学生回答问题时,他会消耗 chalk[i] 支粉笔。如果剩余粉笔数量 严格小于 chalk[i] ,那么学生 i 需要 补充 粉笔。

请你返回需要 补充 粉笔的学生 编号 。

# 题解1: 模拟的优化

记一次遍历完所有学生,所需的粉笔数为 sum, 用 k % sum 则为最后一轮的粉笔数。

最后一轮依次遍历,找出需要补充粉笔的学生编号。

# 代码

var chalkReplacer = function(chalk, k) {
    // 一次所需的粉笔数
    let sum = chalk.reduce((pre,now)=>pre+now)
    let left = k%sum,right=0;
    for(let i=0;i<chalk.length;i++){
        right += chalk[i]
        if(left<right) return i
    }
};

# 题解2: 前缀和 + 二分查找

使用 前缀和 + 二分查找 来优化第二次的遍历

注意: 关于前缀和数组中可能会超出32位整数, 为了避免溢出,在计算前缀和时,将其与k进行比较, ,当前缀和大于k时,就直接返回

# 代码

var chalkReplacer = function(chalk, k) {
    if(chalk[0] > k) return 0
    // 前缀和
    for(let i=1;i<chalk.length;i++){
        chalk[i] += chalk[i-1]
        if(chalk[i]>k) return i
    }
    let sum = chalk[chalk.length-1]
    let target = k%sum;

    let left=0, right=chalk.length-1;
    while(left<right){
        let mid = left+Math.floor((right-left)/2)
        if(target >= chalk[mid]) left = mid+1
        else right = mid
    }
    return left;
};

# 参考资料

  1. 1894. 找到需要补充粉笔的学生编号 (opens new window)
  2. 官方题解 (opens new window)